package day28.homework;

import java.util.Random;

/**
 * 火车站售票系统
 * 四个窗口同时卖票，总共50张票
 * 不能卖出重复的票，
 * 不要卖出编号为负值的票 
 * 每个窗口出票后 随机休眠时间范围在[100,200]ms
 * 该程序演示了多线程环境下的资源共享和线程同步问题
 */
public class hw9 {
    // 总票数，使用static修饰保证所有线程共享同一份数据
    // static关键字确保这个变量属于类而不是某个特定实例
    // 所有TicketWindow线程都会访问和修改这个共享变量
    private static int tickets = 50;
    
    /**
     * 程序入口点
     * 创建并启动四个售票窗口线程
     * @param args 命令行参数
     */
    public static void main(String[] args) {
        // 创建四个售票窗口，分别命名为窗口1、窗口2、窗口3、窗口4
        // 每个窗口都是一个独立的线程对象
        TicketWindow window1 = new TicketWindow("窗口1");
        TicketWindow window2 = new TicketWindow("窗口2");
        TicketWindow window3 = new TicketWindow("窗口3");
        TicketWindow window4 = new TicketWindow("窗口4");
        
        // 启动四个窗口线程，开始并发售票
        // start()方法会调用每个线程的run()方法，使线程进入就绪状态
        window1.start();
        window2.start();
        window3.start();
        window4.start();
    }
    
    /**
     * 售票窗口类
     * 继承Thread类实现多线程售票功能
     * 每个窗口实例代表一个独立的售票窗口线程
     */
    static class TicketWindow extends Thread {
        // 窗口名称，用于标识不同的售票窗口
        // 每个窗口实例都有自己唯一的名称
        private String windowName;
        // 随机数生成器，用于生成随机休眠时间
        // static修饰确保所有窗口实例共享同一个随机数生成器实例
        // 避免每个窗口都创建独立的Random实例，节省资源
        private static Random random = new Random();
        
        /**
         * 构造方法，初始化窗口名称
         * @param windowName 窗口的名称标识
         */
        public TicketWindow(String windowName) {
            // 调用父类Thread的构造方法，设置线程名称
            super(windowName);
            // 将传入的窗口名称赋值给实例变量
            this.windowName = windowName;
        }
        
        /**
         * 线程执行的主要逻辑
         * 重写Thread类的run方法，定义线程的具体执行任务
         * 实现售票的核心逻辑
         */
        @Override
        public void run() {
            // 无限循环，持续售票直到票卖完
            // 使用while(true)循环确保线程持续运行，直到主动break退出
            while (true) {
                // 同步代码块，确保同一时间只有一个线程能进入
                // 使用hw9.class作为锁对象，保证所有窗口线程共享同一把锁
                // synchronized关键字实现线程同步，防止多个线程同时修改共享数据
                synchronized (hw9.class) {
                    // 如果没有票了，停止售票并退出循环
                    // 这是循环的退出条件，当票数小于等于0时结束售票
                    if (tickets <= 0) {
                        // 当票已售完时，打印提示信息
                        System.out.println(windowName + " 发现票已售完，停止售票");
                        // 使用break跳出while循环，结束当前线程的执行
                        break;
                    }
                    
                    // 售出一张票的核心操作：
                    // 1. 获取当前剩余票数（读取操作）
                    // 将当前票数保存到局部变量中，用于后续打印
                    int currentTicket = tickets;
                    // 2. 票数减一（实际售出操作）
                    // 这是关键的修改共享数据的操作，需要在同步块中执行
                    tickets--;
                    
                    // 打印售票信息，显示哪个窗口售出了哪张票
                    // 提供可视化的售票过程跟踪
                    System.out.println(windowName + " 卖出第 " + currentTicket + " 张票，剩余票数：" + tickets);
                }
                
                // 每次售票后随机休眠一段时间，模拟真实售票场景
                // 添加延迟使多线程竞争效果更明显，便于观察程序执行过程
                try {
                    // 生成100-200毫秒的随机休眠时间
                    // nextInt(101)生成0-100的随机数，加上100得到100-200范围
                    int sleepTime = random.nextInt(101) + 100; 
                    // 当前线程休眠指定毫秒数，模拟售票处理时间
                    Thread.sleep(sleepTime);
                } catch (InterruptedException e) {
                    // 处理线程中断异常
                    // 当其他线程调用当前线程的interrupt()方法时会抛出此异常
                    System.err.println(windowName + " 售票过程中被中断");
                    e.printStackTrace();
                }
            }
            // 票卖完后线程自然结束
            // 当while循环结束时，run方法执行完毕，线程生命周期结束
            System.out.println(windowName + " 售票任务完成，线程结束");
        }
    }
}